#pragma once
#include <string>
#include <iostream>
#include <unordered_map>
#include <functional>
#include <cassert>
#include "sock.hpp"
#include "epoller.hpp"
#include "util.hpp"

using namespace std;

namespace tcpserver
{
    class connection;
    class Tcpserver;
    static const uint16_t defaultport = 8080;
    static const int num = 64;
    using func_t = function<void(connection *)>;
    class connection
    {
    public:
        connection(int sock, Tcpserver *tsvr) : _sock(sock), _tsvr(tsvr)
        {
        }
        ~connection()
        {
        }
        void Register(func_t r, func_t s, func_t e)
        {
            _recver = r;
            _sender = s;
            _excepter = e;
        }
        void Close()
        {
            close(_sock);
        }

    public:
        int _sock;
        string _outbuffer; // 输出缓冲区
        string _inbuffer;  // 输入缓冲区
        func_t _recver;    // 读事件
        func_t _sender;    // 写事件
        func_t _excepter;  // 异常事件
        Tcpserver *_tsvr;
        uint64_t _lasttime; // 发生当前事件的时间
    };
    class Tcpserver
    {
    public:
        Tcpserver(func_t func, uint16_t port = defaultport)
            : _service(func), _port(port)
        {
        }
        ~Tcpserver()
        {
            _epoller.Close();
            _sock.Close();
            if(_revs != nullptr)
            {
                delete []_revs;
            }
        }
        void InitServer()
        {
            // 创建sock
            _sock.Socket();
            // 绑定
            _sock.Bind(_port);
            // 监听
            _sock.Listen();
            // 构建epoll模型
            _epoller.Create();
            // 条件listensock与connection的映射表中
            Addconnect(_sock.Fd(), EPOLLIN | EPOLLET, std::bind(&Tcpserver::Accepter, this, std::placeholders::_1), nullptr, nullptr);
            _revs = new struct epoll_event[num];
            _num = num;
            logMessage(NORMAL, "InitServer succeess");
        }
        void Dispatcher()
        {
            int timeout = -1; // 阻塞等待
            while (true)
            {
                Loop(timeout);
            }
        }

    private:
        void Recver(connection *conn)
        {
            conn->_lasttime = time(nullptr);
            while (true)
            {
                char buffer[1024];
                ssize_t s = recv(conn->_sock, buffer, sizeof(buffer) - 1, 0);
                if (s > 0)
                {
                    buffer[s] = 0;
                    conn->_inbuffer += buffer;
                    logMessage(NORMAL,"inbuffer:%s",conn->_inbuffer);
                    _service(conn);
                }
                else if (s == 0)
                {
                    // 异常处理
                    if (conn->_excepter)
                    {
                        conn->_excepter(conn);
                        return;
                    }
                }
                else
                {
                    // 分情况
                    if (errno == EAGAIN || errno == EWOULDBLOCK)
                        break;
                    else if (errno == EINTR)
                        continue;
                    else
                    {
                        // 异常
                        if (conn->_excepter)
                        {
                            conn->_excepter(conn);
                            return;
                        }
                    }
                }
            }
        }
        void Send(connection *conn)
        {
            //对于写端来说正常写都是就绪的，所以我们只需要在其还没有写完的时候让epoll帮我们关心写事件
            //如果写完就不需要epoll帮我们关心了
            conn->_lasttime = time(nullptr);
            while(true)
            {
                ssize_t s = send(conn->_sock,conn->_outbuffer.c_str(),conn->_outbuffer.size(),0);
                if(s > 0)
                {
                    //这里不确定是否一次性就写完了
                    if(conn->_outbuffer.empty())
                    {
                        break;
                    }
                    else{
                        conn->_outbuffer.erase(0,s);
                    }
                }
                else
                {
                    if (errno == EAGAIN || errno == EWOULDBLOCK)
                        break;
                    else if (errno == EINTR)
                        continue;
                    else
                    {
                        // 异常
                        if (conn->_excepter)
                        {
                            conn->_excepter(conn);
                            return;
                        }
                    }
                }
            }
            //这里也有两种情况，写完或者没有写完，对应要有epoll来关心
            if(!conn->_outbuffer.empty())
                EnableReadWrite(conn,true,true);
            else
                EnableReadWrite(conn,true,false);
        }
        void EnableReadWrite(connection* conn,bool readable,bool writeable)
        {
            uint32_t event = (readable?EPOLLIN:0) | (writeable?EPOLLOUT:0) |EPOLLET;
            _epoller.Control(conn->_sock,event,EPOLL_CTL_MOD);
        }
        void Excepter(connection *conn)
        {
            logMessage(DEBUG, "enter into exctpter");
            // 取消epoll对事件的关心
            _epoller.Control(conn->_sock, 0, EPOLL_CTL_DEL);
            // 关闭文件fd
            conn->Close();
            // 清除映射关系
            _connections.erase(conn->_sock);
            logMessage(DEBUG, "清除文件描述符：%d", conn->_sock);
            delete conn;
        }
        void Accepter(connection *conn)
        {
            for (;;)
            {
                string clientip;
                uint16_t clientport;
                int err = 0;
                int sock = _sock.Accept(&clientip, &clientport, &err);
                if (sock > 0)
                {
                    // 给新的sock建立好映射
                    Addconnect(sock, EPOLLIN | EPOLLET,
                               std::bind(&Tcpserver::Recver, this, std::placeholders::_1),
                               std::bind(&Tcpserver::Send, this, std::placeholders::_1),
                               std::bind(&Tcpserver::Excepter, this, std::placeholders::_1));
                    logMessage(NORMAL, "get a new link :[%s:%d]", clientip, clientport);
                }
                else
                {
                    if (err == EAGAIN || err == EWOULDBLOCK)
                        break;
                    else if (err == EINTR)
                        continue;
                    else
                        break;
                }
            }
        }
        void Loop(int timeout)
        {
            // 每一次等待完成之后就可以处理
            int n = _epoller.Wait(_revs, _num, timeout);
            for (int i = 0; i < n; ++i)
            {
                int sock = _revs->data.fd;
                uint32_t event = _revs->events;
                // 如果是异常，那就直接放入读写当中处理
                if (event == EPOLLHUP)
                    event |= (EPOLLIN | EPOLLOUT);
                if (event == EPOLLERR)
                    event |= (EPOLLIN | EPOLLOUT);
                // 读写事件以及就绪，可以处理
                if ((event & EPOLLIN) && IsConnectionExist(sock) && _connections[sock]->_recver)
                    _connections[sock]->_recver(_connections[sock]);
                if ((event & EPOLLOUT) && IsConnectionExist(sock) && _connections[sock]->_sender)
                    _connections[sock]->_sender(_connections[sock]);
            }
        }
        bool IsConnectionExist(int sock)
        {
            auto iter = _connections.find(sock);
            return iter != _connections.end();
        }
        void Addconnect(int sock, uint32_t event, func_t recv, func_t send, func_t except)
        {
            // 如果是ET模式，将sock设置成非阻塞
            if (event & EPOLLET)
                util::SetNonBlock(sock);
            connection *conn = new connection(sock, this);
            // 设置回调方法
            conn->Register(recv, send, except);
            // 让epoll帮我们关心事件
            bool ret = _epoller.AddEvent(event, sock);
            assert(ret);
            (void)ret;
            // 建立映射关系
            _connections.insert(make_pair(sock, conn));
            logMessage(NORMAL, "Addconnect success");
        }

    private:
        uint16_t _port;
        Sock _sock;                                    // listensock
        unordered_map<int, connection *> _connections; // 建立sock和connection的映射关系
        Epoller _epoller;
        struct epoll_event *_revs;
        int _num;
        func_t _service;
    };
}